﻿#pragma once

#include "../MirEnvir/Envir.h"
#include "../MirDatabase/ConquestInfo.h"
#include "GuildObject.h"
#include "../MirEnvir/Map.h"
#include "../../Shared/Enums.h"
#include "SpellObject.h"
#include "NPCObject.h"
#include "PlayerObject.h"
#include "../../Shared/Packet.h"
#include "Monsters/Gate.h"
#include "Monsters/Wall.h"
#include "Monsters/ConquestArcher.h"
#include <string>
#include <unordered_map>
#include <vector>
#include <cmath>
#include <limits>
#include <any>
#include "../../stringhelper.h"

//C# TO C++ CONVERTER NOTE: Forward class declarations:
namespace Server::MirObjects { class ConquestArcherObject; }
namespace Server::MirObjects { class ConquestGateObject; }
namespace Server::MirObjects { class ConquestWallObject; }
namespace Server::MirObjects { class ConquestSiegeObject; }
namespace Server::MirObjects { class ConquestFlagObject; }

using namespace Server::MirEnvir;
using namespace Server::MirDatabase;
using namespace Server::MirObjects::Monsters;

namespace Server::MirObjects
{
    class ConquestObject
    {
    public:
        virtual ~ConquestObject()
        {
            delete Info;
            delete Guild;
            delete ConquestMap;
            delete PalaceMap;
        }

    protected:
        static Server::MirEnvir::Envir *getEnvir();

    public:
        ConquestInfo *Info;

        int Owner = 0;
        GuildObject *Guild;

        int AttackerID = 0;

        Map *ConquestMap;
        Map *PalaceMap;
        std::vector<Map*> ExtraMaps = std::vector<Map*>();

        std::vector<ConquestArcherObject*> ArcherList = std::vector<ConquestArcherObject*>();
        std::vector<ConquestGateObject*> GateList = std::vector<ConquestGateObject*>();
        std::vector<ConquestWallObject*> WallList = std::vector<ConquestWallObject*>();
        std::vector<ConquestSiegeObject*> SiegeList = std::vector<ConquestSiegeObject*>();
        std::vector<ConquestFlagObject*> FlagList = std::vector<ConquestFlagObject*>();

        int ArcherCount = 0;
        int GateCount = 0;
        int WallCount = 0;
        int SiegeCount = 0;

        unsigned int GoldStorage = 0;
        unsigned char npcRate = 0;

        bool NeedSave = false;
    private:
        bool AtWar = false;

    public:
        DateTime WarStartTime;
        DateTime WarEndTime;

        ConquestGame GameType = static_cast<ConquestGame>(0);
        ConquestType StartType = static_cast<ConquestType>(0);

        long long ScheduleTimer = 0;
        long long ScoreTimer = 0;


        static constexpr int MAX_KING_POINTS = 18; //3 minutes
        static constexpr int MAX_CONTROL_POINTS = 6; //1 minute

        std::unordered_map<GuildObject*, int> KingPoints = std::unordered_map<GuildObject*, int>();
        std::unordered_map<ConquestFlagObject*, std::unordered_map<GuildObject*, int>> ControlPoints = std::unordered_map<ConquestFlagObject*, std::unordered_map<GuildObject*, int>>();

        std::vector<SpellObject*> WarEffects = std::vector<SpellObject*>();
        std::vector<NPCObject*> ConquestNPCs = std::vector<NPCObject*>();


        ConquestObject();
        ConquestObject(PlayerObject *owner, const std::string &name);
        ConquestObject(BinaryReader *reader);
        void Save(BinaryWriter *writer);

        bool getWarIsOn() const;
        void setWarIsOn(bool value);

        void LoadArchers();

        void LoadGates();

        void LoadWalls();

        void LoadSieges();

        void LoadFlags();

        void LoadNPCs();

    private:
        void AtWarChanged();

        void NPCVisibility(bool Show = true);

    public:
        bool CheckDay();

        void AutoSchedule();


        void Process();

        void Reset();

        void TakeConquest(PlayerObject *player = nullptr, GuildObject *winningGuild = nullptr);

        void UpdatePlayers(GuildObject *tempGuild);

        void BroadcastGuildName(PlayerObject *player, Packet *p);

    private:
        void CreateZone(bool Create = true);

    public:
        void ScorePoints();

        void StartWar(ConquestGame type);

        void EndWar(ConquestGame type);
    };

    class ConquestSiegeObject
    {
    public:
        virtual ~ConquestSiegeObject()
        {
            delete Info;
            delete Conquest;
            delete Gate;
        }

    protected:
        static Server::MirEnvir::Envir *getEnvir();

    public:
        int Index = 0;
        int Health = 0;

        ConquestSiegeInfo *Info;

        ConquestObject *Conquest;

        Gate *Gate;


        ConquestSiegeObject();
        ConquestSiegeObject(PlayerObject *owner, const std::string &name);
        ConquestSiegeObject(BinaryReader *reader);
        void Save(BinaryWriter *writer);


        void Spawn();

        int GetRepairCost();

        void Repair();
    };

    class ConquestFlagObject
    {
    public:
        int Index = 0;

        ConquestFlagInfo *Info;

        ConquestObject *Conquest;
        GuildObject *Guild;

        NPCObject *Flag;

        virtual ~ConquestFlagObject()
        {
            delete Info;
            delete Conquest;
            delete Guild;
            delete Flag;
        }

        ConquestFlagObject();

        void Spawn();

        void ChangeOwner(GuildObject *guild);

        void UpdateImage();

        void UpdateColour();
    };

    class ConquestWallObject
    {
    public:
        virtual ~ConquestWallObject()
        {
            delete Info;
            delete Conquest;
            delete Wall;
        }

    protected:
        static Server::MirEnvir::Envir *getEnvir();

    public:
        int Index = 0;
        int Health = 0;

        ConquestWallInfo *Info;

        ConquestObject *Conquest;

        Wall *Wall;


        ConquestWallObject();
        ConquestWallObject(PlayerObject *owner, const std::string &name);
        ConquestWallObject(BinaryReader *reader);
        void Save(BinaryWriter *writer);


        void Spawn(bool repair);

        int GetRepairCost();

        void Repair();
    };

    class ConquestGateObject
    {
    public:
        virtual ~ConquestGateObject()
        {
            delete Info;
            delete Conquest;
            delete Gate;
        }

    protected:
        static Server::MirEnvir::Envir *getEnvir();

    public:
        int Index = 0;
        int Health = 0;

        ConquestGateInfo *Info;

        ConquestObject *Conquest;

        Gate *Gate;


        ConquestGateObject();
        ConquestGateObject(PlayerObject *owner, const std::string &name);
        ConquestGateObject(BinaryReader *reader);
        void Save(BinaryWriter *writer);


        void Spawn(bool repair);

        int GetRepairCost();

        void Repair();
    };

    class ConquestArcherObject
    {
    public:
        virtual ~ConquestArcherObject()
        {
            delete Info;
            delete Conquest;
            delete ArcherMonster;
        }

    protected:
        static Server::MirEnvir::Envir *getEnvir();

    public:
        int Index = 0;
        bool Alive = false;

        ConquestArcherInfo *Info;

        ConquestObject *Conquest;

        ConquestArcher *ArcherMonster;


        ConquestArcherObject();
        ConquestArcherObject(PlayerObject *owner, const std::string &name);
        ConquestArcherObject(BinaryReader *reader);
        void Save(BinaryWriter *writer);


        void Spawn(bool Revive = false);

        unsigned int GetRepairCost();
    };
}
